package com.bnyy.medicalHousekeeper.moudle.message;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import androidx.core.content.ContextCompat;

import com.blankj.utilcode.util.FileIOUtils;
import com.bnyy.common.bean.UserInfo;
import com.bnyy.medicalHousekeeper.UserInfoManager;
import com.bnyy.message.bean.Message;
import com.bnyy.message.bean.chat.Chat;
import com.bnyy.message.bean.chat.ChatInfo;
import com.bnyy.message.bean.chat.ChatMessage;
import com.bnyy.message.bean.chat.OfflineChatMessage;
import com.bnyy.message.bean.chat.SendingChatMessage;
import com.bnyy.message.bean.chat.StrangerChat;
import com.bnyy.message.bean.chat.message_data.AlarmMessage;
import com.bnyy.message.bean.chat.message_data.ArticleMessage;
import com.bnyy.message.bean.chat.message_data.GroupChatActivityMessage;
import com.bnyy.message.bean.chat.message_data.GroupChatVoteMessage;
import com.bnyy.message.bean.chat.message_data.HealthWeeklyMessage;
import com.bnyy.message.bean.chat.message_data.InvitationMessage;
import com.bnyy.message.bean.chat.message_data.MallGoodsMessage;
import com.bnyy.message.bean.chat.message_data.MessageData;
import com.bnyy.message.bean.chat.message_data.NoticeAlarmMessage;
import com.bnyy.message.bean.chat.message_data.NoticeGoodsMessage;
import com.bnyy.message.bean.chat.message_data.NoticeLocationAuthorityMessage;
import com.bnyy.message.bean.chat.message_data.ServiceGoodsMessage;
import com.bnyy.message.bean.chat.message_data.TipsMessage;
import com.bnyy.message.bean.chat.message_data.TipsMessageList;
import com.bnyy.message.bean.chat.message_data.UserHomePageMessage;
import com.bnyy.message.bean.chat.message_data.VerificationMessage;
import com.bnyy.message.enums.ChatMessageStatus;
import com.bnyy.message.enums.ChatType;
import com.bnyy.message.enums.MessageType;
import com.bnyy.message.enums.Table;
import com.bnyy.message.event.ChatMessageEvent;
import com.bnyy.message.event.SendMessageEvent;
import com.bnyy.medicalHousekeeper.request.BaseObserverImpl;
import com.bnyy.medicalHousekeeper.request.RequestManager;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import org.greenrobot.eventbus.EventBus;
import org.xutils.DbManager;
import org.xutils.common.util.KeyValue;
import org.xutils.db.Selector;
import org.xutils.db.sqlite.WhereBuilder;
import org.xutils.ex.DbException;
import org.xutils.x;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * Author : 关炳鹏
 * Description :
 * Date : 2022/6/30
 **/
public class MessageManager {
    private static final String TAG = "MessageManager";

    private static final int DB_VERSION = 1;

    public static final int TYPE_TEXT = 4002; // 聊天文字
    public static final int TYPE_AUDIO = 4001; // 聊天语音

    public static final int TYPE_ADD_MEMBER = 4003; // 群聊新增
    public static final int TYPE_REMOVE_MEMBER = 4004; // 群聊移除
    public static final int TYPE_GROUP_DISMISS = 4005; // 群聊解散

    public static final int SEND_TEXT = 0; // 发送的文本
    public static final int SEND_AUDIO = 1; // 发送的语音
    public static final int RECEIVED_TEXT = 2; // 接收的文本
    public static final int RECEIVED_AUDIO = 3; // 接收的语音

    public static final int MAX_AUDIO_DURATION = 15 * 1000;

    public static final int ITEM_COUNT = 50;

    private static MessageManager messageManager;
    private static DbManager dbManager;
    private static Context mContext;
    private static Gson gson;
    private static int loginUserId;
    private static int loginUserRoleId;

    public static void init(Context context) {
        loginUserId = UserInfoManager.getInstance().getLoginUserId();
        loginUserRoleId = UserInfoManager.getInstance().getLoginUserRoleId();

        if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            mContext = context;
            gson = new Gson();
            File parent = new File(context.getExternalFilesDir(null), "/db");
            if (!parent.exists()) {
                parent.mkdir();
            }

            if (dbManager == null) {
                try {
                    x.getDb(
                            new DbManager.DaoConfig()
                                    .setDbDir(parent)
                                    .setDbName("message.db")
                                    .setDbVersion(DB_VERSION)
                                    .setDbUpgradeListener(new DbManager.DbUpgradeListener() {
                                        @Override
                                        public void onUpgrade(DbManager db, int oldVersion, int newVersion) {
                                            Log.e(TAG, "oldVersion = " + oldVersion + " newVersion = " + newVersion);

                                            upgradeDb(db, oldVersion, newVersion);

                                            getOffLineChatMessage(1);
                                        }
                                    })
                                    .setDbOpenListener(new DbManager.DbOpenListener() {
                                        @Override
                                        public void onDbOpened(DbManager db) {
                                            dbManager = db;

                                            int version = db.getDatabase().getVersion();
                                            Log.e(TAG, "db version = " + version);

                                            db.getDatabase().enableWriteAheadLogging();

                                            if (version == DB_VERSION || version == 0) {
                                                getOffLineChatMessage(1);
                                            }
                                        }
                                    })
                    );
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                getOffLineChatMessage(1);
            }
        }
    }

    private MessageManager() {

    }

    private static void upgradeDb(DbManager db, int oldVersion, int newVersion) {

        Log.e(TAG, "upgradeDb oldVersion = " + oldVersion + " newVersion = " + newVersion);
        switch (oldVersion) {
            case 1:
                break;
        }

        oldVersion++;
        if (oldVersion < newVersion) {
            upgradeDb(db, oldVersion, newVersion);
        }
    }

    public static MessageManager getInstance() {
        if (messageManager == null) {
            messageManager = new MessageManager();
        }
        return messageManager;
    }

    public static void sendChatMessage(ChatMessage chatMessage) {
        chatMessage.setRead(true);
        chatMessage.setChatMessageStatus(ChatMessageStatus.SENDING);

        executeSaveOrUpdate(new SendingChatMessage(chatMessage));

        save(chatMessage);

        EventBus.getDefault().post(new SendMessageEvent(chatMessage));
    }

    public static int getUnreadCount(Chat chat) {
        int count = 0;
        try {
            Selector<ChatMessage> selector = dbManager.selector(ChatMessage.class)
                    .where(
                            WhereBuilder.b()
                                    .and(ChatMessage.ColumnName.CHAT_ID, "=", chat.getChatId())
                                    .and(ChatMessage.ColumnName.READ, "=", false)
                    );
            switch (chat.getChatType()) {
                case PRIVATE_CHAT:
                case GROUP_CHAT:
                    selector.and(
                            WhereBuilder.b()
                                    .and(Message.ColumnName.MSG_TYPE, "!=", MessageType.GROUP_CHAT_VERIFICATION.getType())
                                    .and(ChatMessage.ColumnName.STRANGER, "=", false)
                    );
                    break;
                case VERIFICATION:
                    selector.and(
                            WhereBuilder.b()
                                    .and(Message.ColumnName.MSG_TYPE, "=", MessageType.GROUP_CHAT_VERIFICATION.getType())
                    );
                    break;
                case STRANGER:
                    selector = dbManager.selector(ChatMessage.class)
                            .where(
                                    WhereBuilder.b()
                                            .and(Message.ColumnName.RECIPIENT_ID, "=", chat.getLoginUserId())
                                            .and(ChatMessage.ColumnName.READ, "=", false)
                                            .and(ChatMessage.ColumnName.STRANGER, "=", true)
                            );
                    break;
            }
            List<ChatMessage> all = selector.findAll();
            if (all != null) {
                count = all.size();
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return count;
    }

    public static int getTotalUnreadCount() {
        int count = 0;
        try {
            if (dbManager != null) {
                List<ChatMessage> all = dbManager.selector(ChatMessage.class)
                        .where(
                                WhereBuilder.b()
                                        .and(Message.ColumnName.RECIPIENT_ID, "=", loginUserId)
                                        .and(ChatMessage.ColumnName.READ, "=", false)
                        ).findAll();
                if (all != null) {
                    count = all.size();
                }
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return count;
    }

    public static void clearUnreadCount(Chat chat) {
        try {
            switch (chat.getChatType()) {
                case GROUP_CHAT:
//                    dbManager.update(ChatMessage.class, WhereBuilder.b(ChatMessage.ColumnName.CHAT_ID, "=", chat.getChatId())
//                                    .and(WhereBuilder.b()
//                                            .and(ChatMessage.ColumnName.READ, "=", false)
//                                    ),
//                            new KeyValue(ChatMessage.ColumnName.READ, true));
//                    break;
                case PRIVATE_CHAT:
                case STRANGER:
//                    dbManager.update(ChatMessage.class, WhereBuilder.b(ChatMessage.ColumnName.CHAT_ID, "=", chat.getChatId())
//                                    .and(ChatMessage.ColumnName.READ, "=", false),
//                            new KeyValue(ChatMessage.ColumnName.READ, true));
//                    break;
                case VERIFICATION:
//                    dbManager.update(ChatMessage.class, WhereBuilder.b()
//                                    .and(ChatMessage.ColumnName.READ, "=", false)
//                                    .and(ChatMessage.ColumnName.CHAT_ID, "=", chat.getChatId()),
//                            new KeyValue(ChatMessage.ColumnName.READ, true));
//                    break;
                case NOTICE_NEW_FANS:
                case NOTICE_ALARM:
                case NOTICE_LOCATION_AUTHORITY:
                case NOTICE_GOODS:
                    dbManager.update(ChatMessage.class, WhereBuilder.b()
                                    .and(ChatMessage.ColumnName.READ, "=", false)
                                    .and(ChatMessage.ColumnName.CHAT_ID, "=", chat.getChatId()),
                            new KeyValue(ChatMessage.ColumnName.READ, true));
                    break;
            }

            EventBus.getDefault().post(new ChatMessageEvent(ChatMessageEvent.Type.CLEAR_UNREAD_COUNT));
        } catch (DbException e) {
            e.printStackTrace();
        }
    }

    public static ChatMessage getLatestChatMessage(ChatType chatType) {
        try {
            switch (chatType) {
                case PRIVATE_CHAT:
                case GROUP_CHAT:
                    return dbManager.selector(ChatMessage.class)
                            .where(ChatMessage.ColumnName.CHAT_ID, "=", chatType.getChatId())
                            .and(WhereBuilder.b()
                                    .and(Message.ColumnName.MSG_TYPE, "!=", MessageType.GROUP_CHAT_VERIFICATION.getType())
//                                    .and(ChatMessage.ColumnName.STRANGER, "=", false)
                            )
                            .orderBy(Message.ColumnName.TIME, true)
                            .findFirst();
                case VERIFICATION:
                    ChatMessage verificationChatMessage = dbManager.selector(ChatMessage.class)
                            .where(ChatMessage.ColumnName.CHAT_ID, "=", chatType.getChatId())
//                            .where(ChatMessage.ColumnName.CHAT_ID, "=", loginUserId + "_" + ChatType.VERIFICATION.name())
                            .orderBy(Message.ColumnName.TIME, true)
                            .findFirst();
                    if (verificationChatMessage != null) {
                        VerificationMessage verificationMessage = dbManager.selector(VerificationMessage.class)
                                .where(Message.ColumnName.MSG_ID, "=", verificationChatMessage.getMsgId())
                                .findFirst();
                        verificationChatMessage.setMessageData(verificationMessage);
                    }
                    return verificationChatMessage;
                case STRANGER:
                    return dbManager.selector(ChatMessage.class)
                            .where(Message.ColumnName.RECIPIENT_ID, "=", loginUserId)
                            .and(ChatMessage.ColumnName.STRANGER, "=", true)
                            .orderBy(Message.ColumnName.TIME, true)
                            .findFirst();
                case NOTICE_NEW_FANS:
                case NOTICE_ALARM:
                case NOTICE_LOCATION_AUTHORITY:
                case NOTICE_GOODS:
                    return dbManager.selector(ChatMessage.class)
                            .where(ChatMessage.ColumnName.CHAT_ID, "=", chatType.getChatId())
                            .orderBy(Message.ColumnName.TIME, true)
                            .findFirst();
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void sendMessage(Message message) {
        EventBus.getDefault().post(new SendMessageEvent(message));
    }

    public static void logout() {
        EventBus.getDefault().post(new SendMessageEvent(new Message(MessageType.LOGOUT)));
    }

    private static void executeSaveOrUpdate(Object... objects) {
        if (objects.length > 0) {
            for (Object o : objects) {
                Log.e(TAG, "saveOrUpdate " + o.getClass().getSimpleName() + " " + gson.toJson(o));
            }
            try {
                dbManager.saveOrUpdate(Arrays.asList(objects));
            } catch (DbException e) {
                e.printStackTrace();
            }
        }
    }

    public static void save(MessageData messageData) {
        executeSaveOrUpdate(messageData);
    }

    private static void executeSaveOrUpdate(List<?> messages) {
        try {
            for (Object o : messages) {
                Log.e(TAG, "saveOrUpdate " + o.getClass().getSimpleName() + " " + gson.toJson(o));
            }
            dbManager.saveOrUpdate(messages);
        } catch (DbException e) {
            e.printStackTrace();
        }
    }

    public static void updateMessage(Message message, String... columns) {
        try {
            dbManager.update(message, columns);
        } catch (DbException e) {
            e.printStackTrace();
        }
    }

    public static SendingChatMessage getSendingChatMessage(String msgId) {
        try {
            return dbManager.selector(SendingChatMessage.class)
                    .where(SendingChatMessage.ColumnName.MSG_ID, "=", msgId)
                    .findFirst();
        } catch (DbException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void updateSendStatus(String msgId, ChatMessageStatus sendStatus) {
        try {
            int delete = dbManager.delete(SendingChatMessage.class, WhereBuilder.b(SendingChatMessage.ColumnName.MSG_ID, "=", msgId));

            int update = dbManager.update(ChatMessage.class,
                    WhereBuilder.b(Message.ColumnName.MSG_ID, "=", msgId),
                    new KeyValue(Message.ColumnName.SEND_STATUS, sendStatus.getType()));

        } catch (DbException e) {
            e.printStackTrace();
        }
    }

    public static long getTotalCount(WhereBuilder whereBuilder) {
        long count = 0;
        try {
            count = dbManager.selector(Message.class).where(whereBuilder).count();
        } catch (DbException e) {
            e.printStackTrace();
        }
        return count;
    }

    private static int getOffLineChatMessageIndex = 0;

    public static void getOffLineChatMessage(int index) {
        getOffLineChatMessageIndex = index;

        HashMap<String, Integer> params = new HashMap<>();
        params.put("page_index", index);
        params.put("page_size", 200);

        HashMap<String, Long> confirmParams = new HashMap<>();

        RequestManager requestManager = RequestManager.getInstance();
        requestManager.request(requestManager.mMessageRetrofitService.getOffLineChatRecord(RequestManager.getJsonRequestBody(params)),
                new BaseObserverImpl<ArrayList<OfflineChatMessage>>() {
                    @Override
                    public void onSuccess(ArrayList<OfflineChatMessage> offlineChatMessages) {
                        super.onSuccess(offlineChatMessages);

                        int size = offlineChatMessages.size();
                        Log.e(TAG, "getOffLineChatMessage size = " + size);

                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                if (size > 0) {
                                    for (int i = 0; i < size; i++) {
                                        OfflineChatMessage offlineChatMessage = offlineChatMessages.get(i);

                                        Object data = offlineChatMessage.getData();

                                        JsonObject dataRoot = new JsonParser().parse(gson.toJson(data)).getAsJsonObject();

                                        ChatMessage chatMessage = gson.fromJson(dataRoot, ChatMessage.class);

                                        chatMessage.setRecipientRoleId(loginUserRoleId);
                                        chatMessage.setRecipientId(loginUserId);

                                        chatMessage.setMsg_type(offlineChatMessage.getMsg_type());
                                        chatMessage.setChatMessageStatus(ChatMessageStatus.SUCCESS);

                                        MessageData messageData = null;
                                        JsonElement dataJsonElement = dataRoot.get("data");

                                        if (dataJsonElement != null) {
                                            JsonObject dataJsonObject = dataJsonElement.getAsJsonObject();
                                            switch (chatMessage.getMessageType()) {
                                                case MALL_GOODS:
                                                    messageData = gson.fromJson(dataJsonObject, MallGoodsMessage.class);
                                                    break;
                                                case SERVICE_GOODS:
                                                    messageData = gson.fromJson(dataJsonObject, ServiceGoodsMessage.class);
                                                    break;
                                                case ALARM:
                                                    messageData = gson.fromJson(dataJsonObject, AlarmMessage.class);
                                                    break;
                                                case GROUP_CHAT_VERIFICATION:
                                                    messageData = gson.fromJson(dataJsonObject, VerificationMessage.class);
                                                    break;
                                                case GROUP_CHAT_INVITATION:
                                                    messageData = gson.fromJson(dataJsonObject, InvitationMessage.class);
                                                    break;
                                                case USER_HOMEPAGE:
                                                    messageData = gson.fromJson(dataJsonObject, UserHomePageMessage.class);
                                                    break;
                                                case HEALTH_WEEKLY:
                                                    messageData = gson.fromJson(dataJsonObject, HealthWeeklyMessage.class);
                                                    break;
                                                case GROUP_CHAT_VOTE:
                                                    messageData = gson.fromJson(dataJsonObject, GroupChatVoteMessage.class);
                                                    break;
                                                case GROUP_CHAT_ACTIVITY:
                                                    messageData = gson.fromJson(dataJsonObject, GroupChatActivityMessage.class);
                                                    break;
                                                case NOTICE_ALARM:
                                                    messageData = gson.fromJson(dataJsonObject, NoticeAlarmMessage.class);
                                                    break;
                                                case NOTICE_LOCATION_AUTHORITY:
                                                    messageData = gson.fromJson(dataJsonObject, NoticeLocationAuthorityMessage.class);
                                                    break;
                                                case NOTICE_GOODS:
                                                    NoticeGoodsMessage noticeGoodsMessage = gson.fromJson(dataJsonObject, NoticeGoodsMessage.class);
                                                    noticeGoodsMessage.setGoodsJson(gson.toJson(noticeGoodsMessage.getGoodsMessages()));
                                                    messageData = noticeGoodsMessage;
                                                    break;
                                                case CHAT_TIPS:
                                                    if (dataJsonObject.has("keywords")) {
                                                        messageData = new TipsMessageList(chatMessage.getMsgId(), new Gson().toJson(dataJsonObject.get("keywords")));
                                                    }
                                                    break;
                                                case ARTICLE:
                                                    messageData = gson.fromJson(dataJsonObject, ArticleMessage.class);
                                                    break;
                                            }
                                        }
                                        if (messageData != null) {
                                            messageData.setMsgId(chatMessage.getMsgId());
                                            chatMessage.setMessageData(messageData);
                                        }

                                        if (i == offlineChatMessages.size() - 1) {
                                            confirmParams.put("tag", chatMessage.getTag());
                                        }

                                        MessageManager.save(chatMessage);
                                    }

                                    EventBus.getDefault().post(new ChatMessageEvent(ChatMessageEvent.Type.GET_OFF_LINE_CHAT));

                                    if (size == params.get("page_size")) {
//                                        params.put("page_index", params.get("page_index") + 1);
//                                        requestManager.request(requestManager.mMessageRetrofitService.getOffLineChatRecord(RequestManager.getJsonRequestBody(params)), this);
                                        getOffLineChatMessage(getOffLineChatMessageIndex++);
                                    } else {
                                        if (confirmParams.get("tag") != null) {
                                            requestManager.request(requestManager.mMessageRetrofitService.confirmOffLineChatRecord(RequestManager.getJsonRequestBody(confirmParams)),
                                                    new BaseObserverImpl<Object>() {
                                                    });
                                        }
                                    }
                                }
                            }
                        }).start();
                    }
                });
    }

    public static void parse(JsonObject dataRoot) {

    }

    public static String getAudioCachePath(ChatMessage chatMessage) {
        if (chatMessage.getMsg_type() == TYPE_AUDIO) {
            if (!TextUtils.isEmpty(chatMessage.getContent())) {
                File parent = new File(mContext.getExternalCacheDir(), "/audio");
                if (!parent.exists()) {
                    parent.mkdir();
                }
                File file = new File(parent, chatMessage.getMsgId() + ".amr");
                if (!file.exists()) {
                    byte[] decode = Base64.decode(chatMessage.getContent(), Base64.DEFAULT);
                    FileIOUtils.writeFileFromBytesByStream(file, decode);
                }

                return file.getAbsolutePath();
            }
        }
        return "";
    }

    public static String getImageCachePath(String content) {
        File parent = new File(mContext.getExternalCacheDir(), "/image");
        if (!parent.exists()) {
            parent.mkdir();
        }
        File target = new File(parent, System.currentTimeMillis() + ".jpeg");

        byte[] decode = Base64.decode(content, Base64.DEFAULT);
        FileIOUtils.writeFileFromBytesByStream(target, decode);
        return target.getAbsolutePath();
    }

    public static ArrayList<TipsMessage> getTipsMessages(String msgId) {
        ArrayList<TipsMessage> tipsMessages = new ArrayList<>();
        try {
            List<TipsMessage> all = dbManager.selector(TipsMessage.class)
                    .where(Message.ColumnName.MSG_ID, "=", msgId)
                    .findAll();
            if (all != null) {
                tipsMessages.addAll(all);
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return tipsMessages;
    }

    public static MessageData getMessageData(MessageType messageType, String msgId) {
        Log.e(TAG, "getMessageData msgId = " + msgId);
        try {
            switch (messageType) {
                case MALL_GOODS:
                    return dbManager.selector(MallGoodsMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case SERVICE_GOODS:
                    return dbManager.selector(ServiceGoodsMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case ALARM:
                    return dbManager.selector(AlarmMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case GROUP_CHAT_VERIFICATION:
                    return dbManager.selector(VerificationMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case GROUP_CHAT_INVITATION:
                    return dbManager.selector(InvitationMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case USER_HOMEPAGE:
                    return dbManager.selector(UserHomePageMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case HEALTH_WEEKLY:
                    return dbManager.selector(HealthWeeklyMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case GROUP_CHAT_VOTE:
                    return dbManager.selector(GroupChatVoteMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case GROUP_CHAT_ACTIVITY:
                    return dbManager.selector(GroupChatActivityMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case NOTICE_ALARM:
                    return dbManager.selector(NoticeAlarmMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case NOTICE_LOCATION_AUTHORITY:
                    return dbManager.selector(NoticeLocationAuthorityMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case NOTICE_GOODS:
                    return dbManager.selector(NoticeGoodsMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case CHAT_TIPS:
                    return dbManager.selector(TipsMessageList.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
                case ARTICLE:
                    return dbManager.selector(ArticleMessage.class)
                            .where(Message.ColumnName.MSG_ID, "=", msgId)
                            .findFirst();
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取验证消息
     *
     * @return
     */
    public static ArrayList<ChatMessage> getVerificationMessages(String chatId) {
        ArrayList<ChatMessage> verificationMessages = new ArrayList<>();
        try {
            List<ChatMessage> all = dbManager.selector(ChatMessage.class)
                    .where(ChatMessage.ColumnName.CHAT_ID, "=", chatId)
                    .orderBy(Message.ColumnName.TIME, true)
                    .findAll();
            if (all != null) {
                HashMap<Integer, ChatMessage> map = new HashMap<>();
                for (ChatMessage chatMessage : all) {
                    VerificationMessage verificationMessage = (VerificationMessage) getMessageData(chatMessage.getMessageType(), chatMessage.getMsgId());
                    if (verificationMessage != null) {
                        chatMessage.setMessageData(verificationMessage);

                        int enterId = verificationMessage.getEnter_id();
                        if (map.get(enterId) == null) {
                            map.put(enterId, chatMessage);
                        }
                    }
                }
                map.forEach(new BiConsumer<Integer, ChatMessage>() {
                    @Override
                    public void accept(Integer integer, ChatMessage chatMessage) {
                        verificationMessages.add(chatMessage);
                    }
                });
                verificationMessages.sort(new Comparator<ChatMessage>() {
                    @Override
                    public int compare(ChatMessage o1, ChatMessage o2) {
                        if (o1.getTime() > o2.getTime()) {
                            return -1;
                        } else if (o1.getTime() < o2.getTime()) {
                            return 1;
                        } else {
                            return 0;
                        }
                    }
                });
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return verificationMessages;
    }

    public static ArrayList<ChatMessage> getNoticeAlarmMessages() {
        ArrayList<ChatMessage> chatMessages = new ArrayList<>();
        try {
            List<ChatMessage> all = dbManager.selector(ChatMessage.class)
                    .where(ChatMessage.ColumnName.CHAT_ID, "=", loginUserId + "_" + ChatType.NOTICE_ALARM.name())
                    .orderBy(Message.ColumnName.TIME, true)
                    .findAll();

            if (all != null) {
                for (ChatMessage chatMessage : all) {
                    MessageData messageData = getMessageData(MessageType.NOTICE_ALARM, chatMessage.getMsgId());
                    if (messageData != null) {
                        chatMessage.setMessageData(messageData);
                        chatMessages.add(chatMessage);
                    }
                }
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return chatMessages;
    }

    public static ArrayList<ChatMessage> getNoticeGoodsMessages() {
        ArrayList<ChatMessage> chatMessages = new ArrayList<>();
        try {
            List<ChatMessage> all = dbManager.selector(ChatMessage.class)
                    .where(ChatMessage.ColumnName.CHAT_ID, "=", loginUserId + "_" + ChatType.NOTICE_GOODS.name())
                    .orderBy(Message.ColumnName.TIME, true)
                    .findAll();

            if (all != null) {
                for (ChatMessage chatMessage : all) {
                    MessageData messageData = getMessageData(MessageType.NOTICE_GOODS, chatMessage.getMsgId());
                    if (messageData != null) {
                        chatMessage.setMessageData(messageData);
                        chatMessages.add(chatMessage);
                    }
                }
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return chatMessages;
    }

    public static ArrayList<ChatMessage> getNoticeLocationAuthorityMessages() {
        ArrayList<ChatMessage> chatMessages = new ArrayList<>();
        try {
            List<ChatMessage> all = dbManager.selector(ChatMessage.class)
                    .where(ChatMessage.ColumnName.CHAT_ID, "=", loginUserId + "_" + ChatType.NOTICE_LOCATION_AUTHORITY.name())
                    .orderBy(Message.ColumnName.TIME, true)
                    .findAll();

            if (all != null) {
                for (ChatMessage chatMessage : all) {
                    MessageData messageData = getMessageData(MessageType.NOTICE_LOCATION_AUTHORITY, chatMessage.getMsgId());
                    if (messageData != null) {
                        chatMessage.setMessageData(messageData);
                        chatMessages.add(chatMessage);
                    }
                }
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return chatMessages;
    }

    public static ArrayList<ChatMessage> getLatestChatMessages(String chatId) {
        return loadMoreChatMessages(chatId, 0);
    }

    public static ArrayList<ChatMessage> loadMoreChatMessages(String chatId, long baseTime) {

        ArrayList<ChatMessage> chatMessages = new ArrayList<>();

        try {
            Selector<ChatMessage> selector = dbManager.selector(ChatMessage.class)
                    .where(ChatMessage.ColumnName.CHAT_ID, "=", chatId);
            if (baseTime > 0) {
                selector.and(Message.ColumnName.TIME, "<", baseTime);
            }
            List<ChatMessage> all = selector
                    .orderBy(Message.ColumnName.TIME, true)
                    .limit(ITEM_COUNT)
                    .findAll();
            if (all != null) {
                for (ChatMessage chatMessage : all) {
                    Log.e(TAG, "loadMoreChatRecord = " + gson.toJson(chatMessage));
                }

                chatMessages.addAll(all);
                chatMessages.sort(new Comparator<ChatMessage>() {
                    @Override
                    public int compare(ChatMessage o1, ChatMessage o2) {
                        long time1 = o1.getTime();
                        long time2 = o2.getTime();
                        if (time1 > time2) {
                            return 1;
                        } else if (time1 < time2) {
                            return -1;
                        }
                        return 0;
                    }
                });
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return chatMessages;
    }

    /**
     * 获取首页会话列表
     *
     * @return
     */
    public static ArrayList<Chat> getChats() {
        ArrayList<Chat> chats = new ArrayList<>();
        try {

            dbManager.update(ChatMessage.class, WhereBuilder.b(Message.ColumnName.SENDER_ID, "=", loginUserId)
                            .and(Message.ColumnName.SEND_STATUS, "=", ChatMessageStatus.SENDING.getType()),
                    new KeyValue(Message.ColumnName.SEND_STATUS, ChatMessageStatus.FAILURE.getType()));

            List<Chat> all = dbManager.selector(Chat.class)
                    .where(Chat.ColumnName.LOGIN_USER_ID, "=", loginUserId)
                    .orderBy(Message.ColumnName.TIME, true)
                    .findAll();
            if (all != null) {
                chats.addAll(all);
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return chats;
    }

    /**
     * @param chatId
     */
    public static void deleteStrangerChat(String chatId) {
        try {
            dbManager.delete(StrangerChat.class, WhereBuilder.b(ChatMessage.ColumnName.CHAT_ID, "=", chatId));

            dbManager.update(
                    ChatMessage.class,
                    WhereBuilder.b(ChatMessage.ColumnName.CHAT_ID, "=", chatId)
                            .and(ChatMessage.ColumnName.STRANGER, "=", true),
                    new KeyValue(ChatMessage.ColumnName.STRANGER, false)
            );
        } catch (DbException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取当前账号所有陌生人消息
     *
     * @return
     */
    public static ArrayList<StrangerChat> getStrangerChats() {
        ArrayList<StrangerChat> strangerChats = new ArrayList<>();
        try {
            List<StrangerChat> all = dbManager.selector(StrangerChat.class)
                    .where(Chat.ColumnName.LOGIN_USER_ID, "=", loginUserId)
                    .findAll();
            if (all != null) {
                strangerChats.addAll(all);
            }
        } catch (DbException e) {
            e.printStackTrace();
        }
        return strangerChats;
    }

    public static void save(StrangerChat strangerChat) {
        executeSaveOrUpdate(strangerChat);
    }

    public static void save(Chat chat) {
        ChatInfo chatInfo = chat.getChatInfo();
        if (chatInfo != null) {
            save(chatInfo);
            if (chat.getToppingTime() <= 0 && chatInfo.isTopping()) {
                chat.setToppingTime(System.currentTimeMillis());
            }
        }
        if (chat.getTime() == 0) {
            chat.setTime(System.currentTimeMillis());
        }
        executeSaveOrUpdate(chat);
    }

    public static void setChatTopping(Chat chat) {
        switch (chat.getChatType()) {
            case PRIVATE_CHAT:
                setPrivateChatTopping(chat.getRecipientId(), chat.getRecipientRoleId(), chat.getToppingTime() > 0);
                break;
            case GROUP_CHAT:
                setGroupChatTopping(chat.getRecipientId(), chat.getToppingTime() > 0);
                break;
        }
    }

    public static void setGroupChatTopping(int recipientId, boolean topping) {
        setChatTopping(recipientId, -1, ChatType.GROUP_CHAT, topping);
    }

    public static void setPrivateChatTopping(int recipientId, int recipientRoleId, boolean topping) {
        setChatTopping(recipientId, recipientRoleId, ChatType.PRIVATE_CHAT, topping);
    }

    private static void setChatTopping(int recipientId, int recipientRoleId, ChatType chatType, boolean topping) {
        try {
            String chatId = loginUserId + "_" + recipientId;
            if (chatType == ChatType.PRIVATE_CHAT) {
                chatId += "_" + recipientRoleId;
            }
            Chat chat = dbManager.selector(Chat.class)
                    .where(Chat.ColumnName.CHAT_ID, "=", chatId)
                    .findFirst();
            if (chat == null) {
                chat = new Chat(loginUserId, recipientId, recipientRoleId, chatType);
            }
            chat.setToppingTime(topping ? System.currentTimeMillis() : 0);
            save(chat);

            ChatInfo chatInfo = dbManager.selector(ChatInfo.class)
                    .where(ChatInfo.ColumnName.CHAT_ID, "=", chatId)
                    .findFirst();
            if (chatInfo == null) {
                chatInfo = new ChatInfo(chatId);
            }
            chatInfo.setTopping(topping);
            save(chatInfo);
        } catch (DbException e) {
            e.printStackTrace();
        }
    }

    public static void save(ChatInfo chatInfo) {
        executeSaveOrUpdate(chatInfo);
    }

    public static ChatInfo getChatInfo(String chatId) {
        try {
            return dbManager.selector(ChatInfo.class)
                    .where(ChatInfo.ColumnName.CHAT_ID, "=", chatId)
                    .findFirst();
        } catch (DbException e) {
            e.printStackTrace();
        }
        return new ChatInfo(chatId);
    }

    public static void save(ChatMessage chatMessage) {

        long tag = chatMessage.getTag();
        if (tag == 0) {
            return;
        }

        if (tag < 0) {
            chatMessage.setRecipientId(loginUserId);
        }

        if (chatMessage.getSenderId() == loginUserId) {
            chatMessage.setTag(Math.abs(tag));
        }

        if (chatMessage.getTime() == 0) {
            chatMessage.setTime(Math.abs(tag));
        }

        MessageData messageData = chatMessage.getMessageData();
        if (messageData != null) {
            if (messageData.getMessageType() != MessageType.UNKNOWN) {
                save(messageData);
            }
        }

        try {
            Chat chat = new Chat(loginUserId, chatMessage);
            Chat localChat = dbManager.selector(Chat.class).where(Chat.ColumnName.CHAT_ID, "=", chat.getChatId()).findFirst();
            if (localChat == null) {
                localChat = chat;
            } else {
                localChat.setTime(chatMessage.getTime());
            }
            save(localChat);

            if (chat.getChatType() == ChatType.STRANGER) {
                chatMessage.setChatId(loginUserId + "_" + localChat.getRecipientId());
            } else {
                chatMessage.setChatId(localChat.getChatId());
            }
//            switch (chat.getChatType()) {
//                case PRIVATE_CHAT:
//                case GROUP_CHAT:
//                case STRANGER:
//                    chatMessage.setChatId(localChat.getChatId());
//                    break;
//                default:
//                    if (dbManager.selector(Chat.class)
//                            .where(WhereBuilder.b(Chat.ColumnName.LOGIN_USER_ID, "=", loginUserId))
//                            .and(WhereBuilder.b(Chat.ColumnName.CHAT_ID, "=", localChat.getChatId()))
//                            .findFirst() == null) {
////                        chat = new Chat(loginUserId, chat.getChatType());
//                        executeSaveOrUpdate(new Chat(loginUserId, chat.getChatType()));
//                    }
//                    chatMessage.setChatId(localChat.getChatId());
//                    break;
//            }
        } catch (DbException e) {
            e.printStackTrace();
        }

        if (chatMessage.isStranger()) {
            if (chatMessage.getGroupChatId() == 0) {
                save(new StrangerChat(loginUserId, chatMessage));
            }
        }

        ArrayList<Integer> atIds = chatMessage.getAt_ids();
        if (atIds.size() > 0) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < atIds.size(); i++) {
                sb.append(atIds.get(i));
                if (i != atIds.size() - 1) {
                    sb.append("|");
                }
            }
            chatMessage.setAtIds(sb.toString());
        }
        executeSaveOrUpdate(chatMessage);
    }

    public static void update(ChatMessage chatMessage) {
        executeUpdate(chatMessage);
    }

    private static void executeUpdate(Object o) {
        try {
            Log.e(TAG, "update " + gson.toJson(o));
            dbManager.update(o);
        } catch (DbException e) {
            e.printStackTrace();
        }
    }

    public static void save(VerificationMessage verificationMessage) {
        executeSaveOrUpdate(verificationMessage);
    }

    public static void delete(Object o) {
        try {
            Log.e(TAG, "delete " + gson.toJson(o));
            dbManager.delete(o);
        } catch (DbException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除会话包括聊天记录
     *
     * @param chatId
     */
    public static void deleteChat(String chatId) {
        try {
            dbManager.delete(Table.CHAT.getC(), WhereBuilder.b(Chat.ColumnName.CHAT_ID, "=", chatId));
            dbManager.delete(Table.CHAT_INFO.getC(), WhereBuilder.b(ChatInfo.ColumnName.CHAT_ID, "=", chatId));
            dbManager.delete(Table.CHAT_MESSAGE.getC(), WhereBuilder.b(ChatMessage.ColumnName.CHAT_ID, "=", chatId));
        } catch (DbException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除聊天记录
     *
     * @param chatId
     */
    public static void deleteChatMessage(String chatId) {
        try {
            dbManager.delete(Table.CHAT_MESSAGE.getC(), WhereBuilder.b(ChatMessage.ColumnName.CHAT_ID, "=", chatId));
        } catch (DbException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取指定消息id的消息，可用于判断聊天记录是否被清除
     *
     * @param msgId
     * @return
     */
    public static ChatMessage getChatMessage(String msgId) {
        try {
            return (ChatMessage) dbManager.selector(Table.CHAT_MESSAGE.getC())
                    .where(Message.ColumnName.MSG_ID, "=", msgId).findFirst();
        } catch (DbException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取群公告
     *
     * @param chatId
     * @return
     */
    public static ChatMessage getGroupChatNotice(String chatId) {
        try {
            return (ChatMessage) dbManager.selector(Table.CHAT_MESSAGE.getC())
                    .where(ChatMessage.ColumnName.CHAT_ID, "=", chatId)
                    .and(Message.ColumnName.MSG_TYPE, "=", MessageType.GROUP_CHAT_NOTICE.getType())
                    .orderBy(Message.ColumnName.TIME, true)
                    .findFirst();
        } catch (DbException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void printTable(Table... tables) {
//        try {
//            for (Table table : tables) {
//                Log.e(TAG, table.getC().getSimpleName() + " -----");
//                List all = dbManager.selector(table.getC()).findAll();
//                if (all != null) {
//                    for (Object o : all) {
//                        Log.e(TAG, gson.toJson(o));
//                    }
//                }
//                Log.e(TAG, "----- end");
//            }
//
//        } catch (DbException e) {
//            e.printStackTrace();
//        }

        SQLiteDatabase database = dbManager.getDatabase();
        Cursor cursor = database.rawQuery("SELECT * FROM sqlite_master WHERE type = 'table'", null);
        if (cursor.moveToFirst()) {
            do {
//                Log.e(TAG, "cursor = " + Arrays.toString(cursor.getColumnNames()));
                int nameIndex = cursor.getColumnIndex("name");
                String name = cursor.getString(nameIndex);

                Log.e(TAG, name + " -----");
                Cursor cursor1 = database.rawQuery("SELECT  * FROM " + name, null);
//                Cursor cursor1 = database.rawQuery("SELECT  * FROM " + name, null);

                String[] columnNames = cursor1.getColumnNames();
                Log.e(TAG, "columnNames = " + Arrays.toString(columnNames));

                if (cursor1.moveToFirst()) {
                    do {
                        ArrayList<Object> l = new ArrayList<>();

                        for (String columnName : columnNames) {
                            int columnIndex = cursor1.getColumnIndex(columnName);
                            int type = cursor1.getType(columnIndex);
                            switch (type) {
                                case Cursor.FIELD_TYPE_NULL:
                                    break;
                                case Cursor.FIELD_TYPE_INTEGER:
                                    l.add(columnName + " : " + cursor1.getInt(columnIndex));
                                    break;
                                case Cursor.FIELD_TYPE_FLOAT:
                                    l.add(columnName + " : " + cursor1.getFloat(columnIndex));
                                    break;
                                case Cursor.FIELD_TYPE_STRING:
                                    l.add(columnName + " : " + cursor1.getString(columnIndex));
                                    break;
                                case Cursor.FIELD_TYPE_BLOB:
                                    l.add(columnName + " : " + cursor1.getBlob(columnIndex));
                                    break;
                            }
                        }
                        Log.e(TAG, new Gson().toJson(l));
                    } while (cursor1.moveToNext());
                }
                cursor1.close();
                Log.e(TAG, "----- end");
            } while (cursor.moveToNext());
        }
        cursor.close();
    }

    public static void deleteTable(Table... tables) {
        try {
            for (Table table : tables) {
                Log.e(TAG, "deleteTable " + table.getC().getSimpleName() + " -----");
                dbManager.dropTable(table.getC());
                Log.e(TAG, "----- end");
            }

        } catch (DbException e) {
            e.printStackTrace();
        }
    }
}































